﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Benchmark.Db.Base.DataObjects;
using Benchmark.Db.Base.DataCreation;

namespace Benchmark.Db.Base.DataObjects
{
    public delegate object RandomFunctionDelegate(int max);

    public static class RandomMethods
    {
        public static DateTime MIN_DATE = DateTime.Now.AddDays(-90);
        public static DateTime MAX_DATE = DateTime.Now.AddDays(90);

        public static object RandomInt(int max)
        {
            Random random = new Random();
            return random.Next(0, max);
        }

        public static object RandomText(int max)
        {
            max = RandomHelper.Random(max);
            return RandomHelper.RandomText(max);
        }

        public static object RandomTime(int max)
        {
            return RandomHelper.RandomTime(RandomMethods.MIN_DATE, RandomMethods.MAX_DATE);
        }

        public static object RandomGuid(int max)
        {
            return Guid.NewGuid();
        }
    }

    

    public class PropertyMapper<T>
        where T : class, IDataObject, new()
    {
        private static Random random = new Random(DateTime.Now.Millisecond);

        static DateTime MIN_DATE = DateTime.Now.AddDays(-90);
        static DateTime MAX_DATE = DateTime.Now.AddDays(90);

        public Type ObjectType { get; set; }
        public Dictionary<PropertyInfo, PropertyMap> PropertyList = new Dictionary<PropertyInfo, PropertyMap>();

        public class PropertyMap
        {
            public PropertyInfo PropertyInfo { get; set; }
            public RandomFunctionDelegate Delegate { get; set; }
            public int MaxSize { get; set; }
            public bool PrimaryKey { get; set; }
            public string DatabaseFieldType { get; set; }

            public PropertyMap(PropertyInfo propertyInfo)
            {
                this.PropertyInfo = propertyInfo;

                Type propType = this.PropertyInfo.PropertyType;

                if (propType == typeof(int))
                {
                    this.Delegate = RandomMethods.RandomInt;

                    MaxValueAttribute mValAttr = AttributeHelper<MaxValueAttribute, T>.GetAttribute(propertyInfo);
                    if (mValAttr != null)
                        this.MaxSize = mValAttr.maxValue;
                    else
                        this.MaxSize = int.MaxValue;
                }

                if (propType == typeof(string))
                {
                    this.Delegate = RandomMethods.RandomText;
                    object[] attributes = propertyInfo.GetCustomAttributes(typeof(LengthAttribute), true);
                    if (attributes.Length > 0)
                    {
                        LengthAttribute lengthAttribute = (LengthAttribute)attributes[0];
                        this.MaxSize = lengthAttribute.Lenght;
                    }

                    attributes = propertyInfo.GetCustomAttributes(typeof(PrimaryKeyAttribute), true);
                    if (attributes.Length > 0)
                        this.PrimaryKey = true;
                }

                if (propType == typeof(DateTime))
                    this.Delegate = RandomMethods.RandomTime;

                if (propType == typeof(Guid))
                    this.Delegate = RandomMethods.RandomGuid;
            }

            public void SetRandomValue(object obj)
            {
                this.PropertyInfo.SetValue(obj, this.Delegate(this.MaxSize), null);
            }
        }

        public PropertyMapper()
        {
            this.Map();
        }

        private void Map()
        {
            this.ObjectType = typeof(T);

            PropertyInfo[] properties = this.ObjectType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);

            this.PropertyList.Clear();

            foreach (PropertyInfo prop in properties)
                this.PropertyList.Add(prop, new PropertyMap(prop));
        }

        public void SetRandomValues(object obj)
        {
            foreach (PropertyMap map in this.PropertyList.Values)
                map.SetRandomValue(obj);
        }

        public void SetRandomValuesWithoutPrimaryKey(ref object obj)
        {
            foreach (PropertyMap map in this.PropertyList.Values)
                if (!map.PrimaryKey)
                    map.SetRandomValue(obj);
        }
    }
}
